﻿//Copyright (c) 2010 Christopher E. S. King (http://chriskingconsulting.com)
//
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using King.Extensions;
using King.Infoset.Schema;
using King.Infoset.Reflection;
using King.Reflection;

using Target = System.AttributeTargets;

namespace King.Infoset.Entity {

    [AttributeUsage(Target.All), XsAnnotationContract, Order(90)]
    public sealed class AlwaysReturnedAttribute : Attribute { }

    [AttributeUsage(Target.All), XsAnnotationContract, Order(90)]
    public sealed class NeverReturnedAttribute : Attribute { }

    #region Attribute               (Property and Field)
    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(20)]
    public sealed class EntityIdAttribute : Attribute {
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(20)]
    public sealed class VersionAttribute : Attribute {
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(20)]
    public sealed class EntityRefAttribute : Attribute {
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(30)]
    public abstract class RequiredOnAttribute : Attribute {

        #region Private Data Member
        private OperationType m_operationType;
        #endregion

        #region Constructor
        internal RequiredOnAttribute(OperationType operationType) {
            m_operationType = operationType;
        }
        #endregion

        #region Internal Members
        [XsMember(SchemaName = "RequiredOn")]
        internal OperationType OperationType {
            get { return m_operationType; }
        }
        #endregion
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(30)]
    public sealed class RequiredOnCreateAttribute : RequiredOnAttribute {

        #region Constructor
        public RequiredOnCreateAttribute()
            : base(OperationType.Create) { }
        #endregion
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(30)]
    public sealed class RequiredOnUpdateAttribute : RequiredOnAttribute {

        #region Constructor
        public RequiredOnUpdateAttribute()
            : base(OperationType.Update) { }
        #endregion
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(40)]
    public abstract class DisallowedOnAttribute : Attribute {

        #region Private Data Member
        private OperationType m_operationType;
        #endregion

        #region Constructor
        internal DisallowedOnAttribute(OperationType operationType) {
            m_operationType = operationType;
        }
        #endregion

        #region Internal Members
        [XsMember(SchemaName = "DisallowedOn")]
        internal OperationType OperationType {
            get { return m_operationType; }
        }
        #endregion
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(40)]
    public sealed class DisallowedOnCreateAttribute : DisallowedOnAttribute {

        #region Constructor
        public DisallowedOnCreateAttribute()
            : base(OperationType.Create) {
        }
        #endregion
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(45)]
    public sealed class DisallowedOnUpdateAttribute : DisallowedOnAttribute {

        #region Constructor
        public DisallowedOnUpdateAttribute() :
            base(OperationType.Update) {
        }
        #endregion
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(46)]
    public sealed class AllowedWhenAttribute : Attribute {

        #region Constructor
        public AllowedWhenAttribute() { }
        #endregion

        #region Named Members
        [XsMember(Order = 1)]
        public object Status { get; set; }
        #endregion
    }

    [AttributeUsage(Target.Property | Target.Field), XsAnnotationContract, Order(20)]
    public sealed class DefaultOnCreateAttribute : Attribute {

        #region Private Data Members
        private object m_defaultValue;
        #endregion

        #region Constructor
        public DefaultOnCreateAttribute(object defaultValue) {
            m_defaultValue = defaultValue;
        }
        #endregion

        #region Internal Members
        [XsMember(Order = 1, SchemaName = "Default")]
        internal object DefaultValue {
            get { return m_defaultValue; }
        }
        #endregion

        #region Named Members
        [XsMember(Order = 2)]
        public bool HideDefault { get; set; }
        #endregion
    }
    #endregion

    #region Attribute               (Write, OperationType, Update, Create, Reflect)
    [Flags, XsEnumContract()]
    public enum OperationType {
        None = 0,
        Reflect = 1 << 1,
        Get = 1 << 2,
        Parent = 1 << 3,
        Set = 1 << 4,
        Add = 1 << 5,
        Remove = 1 << 6,
        Create = 1 << 7,
        CreateOne = 1 << 8,
        Update = 1 << 9,
    }

    [XsAnnotationContract]
    public abstract class OperationTypeAttribute : Attribute {

        #region Private Data Members
        private OperationType m_operationType;
        #endregion

        #region Constructor
        internal OperationTypeAttribute(OperationType operationType) {
            m_operationType = operationType;
        }
        #endregion

        #region Internal Members
        [XsMember]
        internal OperationType OperationType {
            get { return m_operationType; }
        }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(15)]
    public class ParentAttribute : OperationTypeAttribute {

        #region Constructor
        public ParentAttribute() : base(OperationType.Get) { }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(15)]
    public class GetAttribute : OperationTypeAttribute {

        #region Constructor
        public GetAttribute() : base(OperationType.Get) { }
        #endregion

        #region Public Members
        [XsMember]
        public string SingularNoun { get; set; }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(15)]
    public class WriteAttribute : Attribute {

        #region Constructor
        public WriteAttribute() { }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(10)]
    public sealed class UpdateAttribute : OperationTypeAttribute {

        #region Constructor
        public UpdateAttribute() : base(OperationType.Update) { }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(10)]
    public sealed class CreateAttribute : OperationTypeAttribute {

        #region Constructor
        public CreateAttribute() : base(OperationType.Create) { }
        #endregion
    }

    [AttributeUsage(Target.Field | Target.Property), XsAnnotationContract, Order(10)]
    public sealed class CreateOnAssociateAttribute : Attribute {

        #region Private Members
        private string m_createOperationName;
        #endregion

        #region Constructor
        public CreateOnAssociateAttribute(string createOperationName) {
            m_createOperationName = createOperationName;
        }
        #endregion

        #region Public Members
        [XsMember]
        public string CreateOperationName { get { return m_createOperationName; } }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(10)]
    public sealed class SetAttribute : OperationTypeAttribute {

        #region Constructor
        public SetAttribute() : base(OperationType.Set) { }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(10)]
    public sealed class AddAttribute : OperationTypeAttribute {

        #region Constructor
        public AddAttribute() : base(OperationType.Add) { }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(10)]
    public sealed class RemoveAttribute : OperationTypeAttribute {

        #region Constructor
        public RemoveAttribute() : base(OperationType.Remove) { }
        #endregion
    }

    [AttributeUsage(Target.Method), XsAnnotationContract, Order(10)]
    public sealed class RefreshAttribute : OperationTypeAttribute {

        #region Constructor
        public RefreshAttribute() : base(OperationType.Reflect) { }
        #endregion
    }
    #endregion
}

